/**
 * <one line to give the program's name and a brief idea of what it does.>
 * Copyright (C) Aug 1, 2011  Isaias
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package redclient.webclient;

import java.io.BufferedOutputStream;
import java.net.URL;
import java.net.MalformedURLException;
import java.io.IOException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.SocketException;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.jsoup.Jsoup;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
import redclient.Items.CustomField;
import redclient.Items.Issue;
import redclient.Items.Project;
import redclient.RedmineCredentials;

/**
 *
 * @author Isaias
 * @file WebClient.java
 */
public class WebClient {

    private String url;

    private String authenticityToken;
    
    private RedmineCredentials credentials;
    
    private String cookieValue;
    

    public WebClient(RedmineCredentials credentials) throws WebClientException
    {
        this.credentials = credentials;
        this.Login();
    }

    public Document getProjects() throws WebClientException
    {
        Document doc = null;
        try
        {
            url = credentials.getHost();
            if ( url.endsWith("/") )
            {
                url = url.substring(0, url.length()-1);
            }
            URL proyectsUrl = new URL(url + "/projects.xml");
            if( credentials.getProxyhost() != null && credentials.getProxyhost().length() > 0 )
            {
                proyectsUrl = new URL(proyectsUrl.getProtocol(), credentials.getProxyhost(), credentials.getProxyport(), url + "/projects.xml");
            }

            HttpURLConnection redmine = (HttpURLConnection)proyectsUrl.openConnection();
            redmine.setRequestProperty("Cookie", cookieValue);
            redmine.setDoOutput(true); // Setting HTTP method to POST

            // Write user credentials to request
            String headerName=null;
            for (int i=1; (headerName = redmine.getHeaderFieldKey(i))!=null; i++) {
                if (headerName.equals("Set-Cookie")) {                  
                    cookieValue = redmine.getHeaderField(i);
                    cookieValue = cookieValue.substring(0, cookieValue.indexOf(";"));
                    break;
                }
            }
                
            String responseStatus = redmine.getHeaderField("Status");

            if ( "200".equals(responseStatus) )
            {
                DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
                DocumentBuilder builder = factory.newDocumentBuilder();
                doc =  builder.parse(redmine.getInputStream());
                redmine.getInputStream().close();
            }
            else
            {
                throw new WebClientException("Server did not respond correctly");
            }
        }
        catch(MalformedURLException mue)
        {
            throw new WebClientException("Redmine server URL is not well formed", mue);
        }
        catch(IOException ioe)
        {
            throw new WebClientException("There was a error trying to retrieve the projects' information", ioe);
        }
        catch(ParserConfigurationException pce)
        {
            throw new WebClientException("Unexpected error retrieving projects' information", pce);
            //TODO: Log this event
        }catch(SAXException saxe)
        {
            throw new WebClientException("Unexpected error retrieving projects' information", saxe);
            //TODO: Log this event
        }
        return doc;
    }

    public Document getIssues(int page) throws WebClientException
    {
        Document doc = null;
        try
        {
            url = credentials.getHost();
            if ( url.endsWith("/") )
            {
                url = url.substring(0, url.length()-1);
            }
            URL proyectsUrl = new URL(url + "/issues.xml?page="+page);
            if( credentials.getProxyhost() != null && credentials.getProxyhost().length() > 0 )
            {
                proyectsUrl = new URL(proyectsUrl.getProtocol(), credentials.getProxyhost(), credentials.getProxyport(), url + "/issues.xml?page="+page);
            }

            HttpURLConnection redmine = (HttpURLConnection)proyectsUrl.openConnection();
            redmine.setRequestProperty("Cookie", cookieValue);
            
            // Setting HTTP method to POST
            redmine.setDoOutput(true);
            String headerName=null;
            for (int i=1; (headerName = redmine.getHeaderFieldKey(i))!=null; i++) {
                if (headerName.equals("Set-Cookie")) {                  
                    cookieValue = redmine.getHeaderField(i);
                    cookieValue = cookieValue.substring(0, cookieValue.indexOf(";"));
                    break;
                }
            }
                
            // Write user credentials to request
            String responseStatus = redmine.getHeaderField("Status");
            if ( "200".equals(responseStatus) )
            {
                DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
                DocumentBuilder builder = factory.newDocumentBuilder();
                doc =  builder.parse(redmine.getInputStream());
                redmine.getInputStream().close();
            }
            else
            {
                throw new WebClientException("Server did not respond correctly");
            }
        }
        catch(MalformedURLException mue)
        {
            throw new WebClientException("Redmine server URL is not well formed", mue);
        }
        catch(IOException ioe)
        {
            throw new WebClientException("There was a error trying to retrieve the issues' information", ioe);
        }
        catch(ParserConfigurationException pce)
        {
            throw new WebClientException("Unexpected error retrieving issues' information", pce);
            //TODO: Log this event
        }catch(SAXException saxe)
        {
            throw new WebClientException("Unexpected error retrieving issues' information", saxe);
            //TODO: Log this event
        }
        return doc;
    }

    protected void Login() throws WebClientException
    {
        OutputStream os = null;
        InputStream is = null;
        String status = null;
        HttpURLConnection.setFollowRedirects(false);
        try
        {
            url = credentials.getHost();
            if ( url.endsWith("/") )
            {
                url = url.substring(0, url.length()-1);
            }
            // Meking first request to ob
            URL loginPage = new URL(url + "/login");
            if( credentials.getProxyhost() != null && credentials.getProxyhost().length() > 0 )
            {
                loginPage = new URL(loginPage.getProtocol(), credentials.getProxyhost(), credentials.getProxyport(), url + "/login");
            }
            HttpURLConnection redmine = (HttpURLConnection)loginPage.openConnection();
            redmine.setInstanceFollowRedirects(false);
            
            String headerName=null;
            for (int i=1; (headerName = redmine.getHeaderFieldKey(i))!=null; i++) {
                if (headerName.equals("Set-Cookie")) {                  
                    cookieValue = redmine.getHeaderField(i);
                    cookieValue = cookieValue.substring(0, cookieValue.indexOf(";"));
                    break;
                }
            }

            is = redmine.getInputStream();
            org.jsoup.nodes.Document doc = Jsoup.parse(is, "UTF-8", url.toString());
            
            authenticityToken = doc.select("input[name=authenticity_token]").attr("value");
            
            doc = null;
            
            redmine = (HttpURLConnection)loginPage.openConnection();
            redmine.setRequestProperty("Cookie", cookieValue);
            redmine.setInstanceFollowRedirects(false);
            redmine.setDoOutput(true);
            redmine.setUseCaches(false);

            // Write user credentials to request
            os = redmine.getOutputStream();
            StringBuilder sb = new StringBuilder();
            sb.append("authenticity_token=").append(URLEncoder.encode(authenticityToken, "utf8")).append("&")
              .append("username=").append(URLEncoder.encode(credentials.getUsername(), "utf8")).append("&")
              .append("password=").append(URLEncoder.encode(credentials.getPassword(), "utf8")).append("&")
              .append("login=Login");
            
            os.write(sb.toString().getBytes());
            os.flush();
            os.close();
            redmine.getInputStream();
            //String headerName = null;
            for (int i=1; (headerName = redmine.getHeaderFieldKey(i))!=null; i++) {
                if (headerName.equals("Set-Cookie")) {                  
                    cookieValue = redmine.getHeaderField(i);
                    cookieValue = cookieValue.substring(0, cookieValue.indexOf(";"));
                }
                else if(headerName.equals("Status"))
                {
                    status = redmine.getHeaderField(i);
                }
            }
            if ( "302".equals(status) || "200".equals(status) )
            {
               System.out.println("User logged successfuly");
            }
            else
            {
                throw new WebClientException("Could not log in to " + this.url);
            }
        }
        catch(MalformedURLException mue)
        {
            throw new WebClientException(
                        String.format("URL [%1$s] is invalid or not well formed for instance [%2$s]",
                                credentials.getHost(),
                                credentials.getInstanceName()
                        ), 
                        mue);
        }
        catch(SocketException se)
        {
            throw new WebClientException(
                        String.format("There was a network error trying to connect to intance [%1$s] on [%2$s], "
                                    +" please verify your network conectivity", 
                                    credentials.getInstanceName(),
                                    credentials.getHost()
                        ), 
                        se);
        }
        catch(IOException ioe)
        {
            throw new WebClientException(
                        String.format("There was a error trying to log in to instance [%1$s] at [%2$s]",
                                    credentials.getInstanceName(),
                                    credentials.getHost()
                        ),
                        ioe);
        }
        finally
        {
            if( os != null )
            {
                try
                {
                    os.close();
                }
                catch(IOException ioe)
                {
                    //TODO: Uncomment ioe.printStackTrace();
                }
            }
            if( is != null )
            {
                try
                {
                    is.close();
                }
                catch(IOException ioe)
                {
                    //TODO: Uncomment ioe.printStackTrace();
                }
            }
        }
         
    }

    public org.jsoup.nodes.Document GetNewIssueForm(Project project, Issue issue, String token, String action)  throws WebClientException
    {
        org.jsoup.nodes.Document doc = null;
        OutputStream os = null;
        InputStream is = null;
        try
        {
            url = credentials.getHost();
            if ( url.endsWith("/") )
            {
                url = url.substring(0, url.length()-1);
            }
            URL proyectsUrl = new URL(url + "/projects/"+project.getProjectId()+"/issues/new" + (issue != null ? "?id=" : ""));
            if( credentials.getProxyhost() != null && credentials.getProxyhost().length() > 0 )
            {
                proyectsUrl = new URL(proyectsUrl.getProtocol(), credentials.getProxyhost(), credentials.getProxyport(), url + "/projects/"+project.getProjectId()+"/issues/new"+ (issue != null ? "?id=" : ""));
            }

            HttpURLConnection redmine = (HttpURLConnection)proyectsUrl.openConnection();

            // Setting HTTP method to POST
            redmine.setInstanceFollowRedirects(true);
            redmine.setRequestProperty("Cookie", cookieValue);
            redmine.setRequestProperty("Referer", url + "projects/"+project.getIdentifier()+"/issues/new");
            redmine.setRequestProperty("Connection", "Keep-Alive");
            /*
            if( issue != null )
            {
                redmine.setDoOutput(true);
                os = redmine.getOutputStream();
                
                StringBuilder sb = new StringBuilder();
                
                sb.append("authenticity_token=").append(URLEncoder.encode(token, "utf8")).append("&")
                  .append("commit=").append(URLEncoder.encode(action, "utf8")).append("&");
                        
                Map<String, Object> parameters = issue.getPostData();
                for(String s : parameters.keySet())
                {
                    Object value = parameters.get(s);
                    if( value instanceof String || value == null)
                    {
                        sb.append(s).append("=").append(value != null ? URLEncoder.encode((String)value, "utf8") : "").append("&");
                    }
                    else
                    {
                        throw new WebClientException("Don't now what you are trying" + s);
                    }
                }
                os.write(sb.toString().getBytes());
                os.flush();
                os.close();
            }
             * 
             */
            String headerName=null;
            for (int i=1; (headerName = redmine.getHeaderFieldKey(i))!=null; i++) {
                if (headerName.equals("Set-Cookie")) {                  
                    cookieValue = redmine.getHeaderField(i);
                    cookieValue = cookieValue.substring(0, cookieValue.indexOf(";"));
                    break;
                }
            }
            String responseStatus = redmine.getHeaderField("Status");
            if ( "200".equals(responseStatus) )
            {
                try
                {
                    is = redmine.getInputStream();
                    doc = Jsoup.parse(is, "UTF-8", url.toString());
                }
                catch(IOException ioe)
                {
                    throw new WebClientException("Could not parse server response", ioe);
                }
            }
            else
            {
                throw new WebClientException("Server did not respond correctly");
            }
        }
        catch(MalformedURLException mue)
        {
            throw new WebClientException("Redmine server URL is not well formed", mue);
        }
        catch(SocketException se)
        {
            throw new WebClientException("There was a network error, please verify your network conectivity", se);
        }
        catch(IOException ioe)
        {
            throw new WebClientException("There was a error trying to retrieve the issue form information", ioe);
        }
        finally
        {
            if( os != null )
            {
                try
                {
                    os.close();
                }
                catch(IOException ioe)
                {
                    //TODO: Uncomment ioe.printStackTrace();
                }
            }
            if( is != null )
            {
                try
                {
                    is.close();
                }
                catch(IOException ioe)
                {
                    //TODO: Uncomment ioe.printStackTrace();
                }
            }
        }
        return doc;
    }

    private String UTF8_URLEncode(Object value)
    {
        String result = null;
        try
        {
            result = URLEncoder.encode(value.toString(), "UTF-8");
        }
        catch(UnsupportedEncodingException uee)
        {
            //do nothig
        }
        return value.toString();
    }
    
    public org.jsoup.nodes.Document SaveNewIssue(Issue issue, String token, File[] files, String[] fileDesc) throws WebClientException
    {

        org.jsoup.nodes.Document doc = null;
        BufferedOutputStream bos = null;
        InputStream is = null;
        try
        {
            url = credentials.getHost();
            if ( url.endsWith("/") )
            {
                url = url.substring(0, url.length()-1);
            }
            URL proyectsUrl = new URL(url + "/projects/"+issue.getProject().getIdentifier()+"/issues");
            if( credentials.getProxyhost() != null && credentials.getProxyhost().length() > 0 )
            {
                proyectsUrl = new URL(proyectsUrl.getProtocol(), credentials.getProxyhost(), credentials.getProxyport(), url + "/projects/"+issue.getProject().getIdentifier()+"/issues");
            }

            HttpURLConnection redmine = (HttpURLConnection)proyectsUrl.openConnection();

            // Setting HTTP method to POST
            redmine.setDoOutput(true);

            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
            String separator = "-----------------------------" + sdf.format(new Date());

            String postData = encapsulateIssue(issue, token, separator);
            byte[] bytes = postData.getBytes();

            redmine.setInstanceFollowRedirects(true);
            redmine.setRequestProperty("Cookie", cookieValue);
            redmine.setRequestProperty("X-Redmine-API-Key", "1be694bf256766c6d74d2ab2c83b5f31b2569cb6");
            redmine.setRequestProperty("Referer", url + "projects/"+issue.getProject().getIdentifier()+"/issues/new");
            redmine.setRequestProperty("Connection", "Keep-Alive");
            redmine.setRequestProperty("Content-Type", "multipart/form-data; boundary="+separator.substring(2));

            bos = new BufferedOutputStream(redmine.getOutputStream());

            if( files != null && files.length > 0)
            {
                for(int i = 0; i < files.length; i++)
                {
                    File file = files[i];
                    String header = null;
                    byte[] data = null;
                    header = separator + "\r\n"
                             + "Content-Disposition: form-data; name=\"attachments["+(i+1)+"][file]\"; filename=\""
                             + URLEncoder.encode(file.getName(), "UTF-8") + "\"\r\n"
                             + "Content-Type: application/octet-stream" + "\r\n\r\n";

                    data = header.getBytes();
                    bos.write(data);

                    // write file to stream
                    writeFileToStream(bos, file);

                    header = "\r\n" + separator + "\r\n"
                             +"Content-Disposition: form-data; name=\"attachments["+(i+1)+"][description]\""
                             +"\r\n\r\n"+fileDesc[i]+"\r\n";
                    data = header.getBytes();
                    bos.write(data);
                    header = null;
                }
            }

            bos.write(bytes);
            bos.flush();
            bos.close();
            String headerName=null;
            for (int i=1; (headerName = redmine.getHeaderFieldKey(i))!=null; i++) {
                if (headerName.equals("Set-Cookie")) {                  
                    cookieValue = redmine.getHeaderField(i);
                    cookieValue = cookieValue.substring(0, cookieValue.indexOf(";"));
                    break;
                }
            }
            String responseStatus = redmine.getHeaderField("Status");
            if ( "200".equals(responseStatus) || "302".equals(responseStatus) )
            {
                try
                {
                    is = redmine.getInputStream();
                    doc = Jsoup.parse(is, "UTF-8", url.toString());
                }
                catch(IOException ioe)
                {
                    throw new WebClientException("Could not parse server response", ioe);
                }
            }
            else
            {
                throw new WebClientException("Server did not respond correctly");
            }
        }
        catch(MalformedURLException mue)
        {
            throw new WebClientException("Redmine server URL is not well formed", mue);
        }
        catch(SocketException se)
        {
            throw new WebClientException("There was a network error, please verify your network conectivity", se);
        }
        catch(IOException ioe)
        {
            throw new WebClientException("There was a error trying to send the issue description", ioe);
        }
        finally
        {
            if( bos != null )
            {
                try
                {
                    bos.close();
                }
                catch(IOException ioe)
                {
                    //TODO: Uncomment ioe.printStackTrace();
                }
            }
            if( is != null )
            {
                try
                {
                    is.close();
                }
                catch(IOException ioe)
                {
                    //TODO: Uncomment ioe.printStackTrace();
                }
            }
        }
        return doc;
    }
    
    private String encapsulateIssue(Issue issue, String token, String separator)
    {
        
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        StringBuilder sb = new StringBuilder();
        sb.append(separator).append("\r\n")
          .append("Content-Disposition: form-data; name=\"authenticity_token\"")
          .append("\r\n\r\n").append(UTF8_URLEncode(token)).append("\r\n")
          .append(separator).append("\r\n")
          .append("Content-Disposition: form-data; name=\"issue[is_private]\"")
          .append("\r\n\r\n").append("0").append("\r\n")
          .append(separator).append("\r\n")
          .append("Content-Disposition: form-data; name=\"issue[tracker_id]\"")
          .append("\r\n\r\n").append(UTF8_URLEncode(issue.getTrakerId())).append("\r\n")
          .append(separator).append("\r\n")
          .append("Content-Disposition: form-data; name=\"issue[subject]\"")
          .append("\r\n\r\n").append(UTF8_URLEncode(issue.getSubject())).append("\r\n")
          .append(separator).append("\r\n")
          .append("Content-Disposition: form-data; name=\"issue[description]\"")
          .append("\r\n\r\n").append(UTF8_URLEncode(issue.getDescription())).append("\r\n")
          .append(separator).append("\r\n")
          .append("Content-Disposition: form-data; name=\"issue[status_id]\"")
          .append("\r\n\r\n").append(UTF8_URLEncode(issue.getStatusId())).append("\r\n")
          .append(separator).append("\r\n")
          .append("Content-Disposition: form-data; name=\"issue[priority_id]\"")
          .append("\r\n\r\n").append(UTF8_URLEncode(issue.getPriorityId())).append("\r\n")
          .append(separator).append("\r\n")
          .append("Content-Disposition: form-data; name=\"issue[assigned_to_id]\"")
          .append("\r\n\r\n").append(UTF8_URLEncode(
                issue.getAssignedToId() == -1 ? "" : issue.getAssignedToId()
                )).append("\r\n")
          .append(separator).append("\r\n")
          .append("Content-Disposition: form-data; name=\"issue[parent_issue_id]\"")
          .append("\r\n\r\n").append(UTF8_URLEncode(issue.getParentIssueId())).append("\r\n")
          .append(separator).append("\r\n")
          .append("Content-Disposition: form-data; name=\"issue[start_date]\"")
          .append("\r\n\r\n").append(UTF8_URLEncode(df.format(issue.getStartDate()))).append("\r\n")
          .append(separator).append("\r\n")
          .append("Content-Disposition: form-data; name=\"issue[due_date]\"")
          .append("\r\n\r\n").append(UTF8_URLEncode(
                issue.getDueDate() != null ? df.format(issue.getDueDate()) : ""
                )).append("\r\n")
          .append(separator).append("\r\n")
          .append("Content-Disposition: form-data; name=\"issue[estimated_hours]\"")
          .append("\r\n\r\n").append(UTF8_URLEncode(
                issue.getEstimatedHours() < 0 ? "" : issue.getEstimatedHours()
                )).append("\r\n")
          .append(separator).append("\r\n")
          .append("Content-Disposition: form-data; name=\"issue[done_ratio]\"")
          .append("\r\n\r\n").append(UTF8_URLEncode(issue.getDoneRation())).append("\r\n");
        
        if( issue.getCustomFileds() != null && issue.getCustomFileds().size() > 0 )
        {
            for(CustomField cf : issue.getCustomFileds())
            {
                sb.append(separator).append("\r\n")
                  .append("Content-Disposition: form-data; name=\"")
                  .append(UTF8_URLEncode(cf.getName()))
                  .append("\"")
                  .append("\r\n\r\n").append(UTF8_URLEncode(cf.getValue())).append("\r\n");
            }
        }

        sb.append(separator).append("\r\n")
          .append("Content-Disposition: form-data; name=\"continue\"")
          .append("\r\n\r\n").append(UTF8_URLEncode("Create and continue")).append("\r\n")
          .append(separator).append("--\r\n");

        return sb.toString();
    }
    
    int writeFileToStream(OutputStream dos, File file) throws WebClientException
    {
        int bytesWriten = 0;
        try
        {
            FileInputStream fis = new FileInputStream(file);
            byte[] buffer = new byte[1024];
            int bytesRead = 0;
            while((bytesRead = fis.read(buffer)) != -1)
            {
                dos.write(buffer, 0, bytesRead);
                bytesWriten += bytesRead;
            }
            fis.close();
        }
        catch(FileNotFoundException fnfw)
        {
            throw new WebClientException(String.format("File [%s] was not found", file.getAbsolutePath()), fnfw);
        }
        catch(IOException ioe)
        {
            throw new WebClientException(String.format("Error while trying to read file [%s],\r\nPlease verify that the file exists and that you read access.", file.getAbsolutePath()), ioe);
        }
        return bytesWriten;
    }
    
    public org.jsoup.nodes.Document GetNewLogTime(Issue issue) throws WebClientException
    {
        org.jsoup.nodes.Document doc = null;
        OutputStream os = null;
        InputStream is = null;
        try
        {
            url = credentials.getHost();
            if ( url.endsWith("/") )
            {
                url = url.substring(0, url.length()-1);
            }
            URL proyectsUrl = new URL(url + "/issues/" + issue.getId() + "/time_entries/new");
            if( credentials.getProxyhost() != null && credentials.getProxyhost().length() > 0 )
            {
                proyectsUrl = new URL(proyectsUrl.getProtocol(), 
                                        credentials.getProxyhost(), 
                                        credentials.getProxyport(), 
                                        url + "/issues/" + issue.getId() + "/time_entries/new");
            }

            HttpURLConnection redmine = (HttpURLConnection)proyectsUrl.openConnection();

            // Setting HTTP method to POST
            redmine.setInstanceFollowRedirects(true);
            redmine.setRequestProperty("Referer", url + "/issues/" + issue.getId() + "/time_entries/new");
            redmine.setRequestProperty("Cookie", cookieValue);
            redmine.setRequestProperty("Connection", "Keep-Alive");
            
            String headerName=null;
            for (int i=1; (headerName = redmine.getHeaderFieldKey(i))!=null; i++) {
                if (headerName.equals("Set-Cookie")) {                  
                    cookieValue = redmine.getHeaderField(i);
                    cookieValue = cookieValue.substring(0, cookieValue.indexOf(";"));
                    break;
                }
            }
            String responseStatus = redmine.getHeaderField("Status");
            if ( "200".equals(responseStatus) )
            {
                try
                {
                    is = redmine.getInputStream();
                    doc = Jsoup.parse(is, "UTF-8", url.toString());
                }
                catch(IOException ioe)
                {
                    throw new WebClientException("Could not parse server response", ioe);
                }
            }
            else
            {
                throw new WebClientException("Server did not respond correctly");
            }
        }
        catch(MalformedURLException mue)
        {
            throw new WebClientException("Redmine server URL is not well formed", mue);
        }
        catch(SocketException se)
        {
            throw new WebClientException("There was a network error, please verify your network conectivity", se);
        }
        catch(IOException ioe)
        {
            throw new WebClientException("There was a error trying to retrieve the issue form information", ioe);
        }
        finally
        {
            if( os != null )
            {
                try
                {
                    os.close();
                }
                catch(IOException ioe)
                {
                    //TODO: Uncomment ioe.printStackTrace();
                }
            }
            if( is != null )
            {
                try
                {
                    is.close();
                }
                catch(IOException ioe)
                {
                    //TODO: Uncomment ioe.printStackTrace();
                }
            }
        }
        return doc;
    }
}